/*
 * lex_common.h
 * This file is part of gURL
 *
 * Copyright (C) 2014 - Aleksey Konovalov
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Library General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#pragma once

#include <gtk/gtk.h>

#define MARK_TEXT(ATTRS) mark_text(yyextra, yytext, yyleng, ATTRS)
#define MARK_EOL() mark_eol(yyextra)
#define RESET_INDENT() reset_indent(yyextra)
#define INC_INDENT() inc_indent(yyextra)
#define DEC_INDENT() dec_indent(yyextra)
#define IGNORE_TEXT()

#define DO_HIGHLIGHT(prefix, tb, text, len, prettyprint)              \
{                                                                     \
    gchar* tmp = g_malloc(len + 2);                                   \
    memcpy(tmp, text, len);                                           \
    size_t index_capacity = 0, index_len = 0;                         \
    GArray* lines_index = g_array_new(FALSE, FALSE, sizeof(gchar*));  \
    g_array_append_val(lines_index, tmp);                             \
    for(size_t i = 0; i < len; ++i) {                                 \
        if(tmp[i] == '\r' || tmp[i] == '\n') {                        \
            gchar* pos = tmp + i + 1;                                 \
            if(i + 1 < len && tmp[i] == '\r' && tmp[i + 1] == '\n') { \
                ++pos;                                                \
                ++i;                                                  \
            }                                                         \
            g_array_append_val(lines_index, pos);                     \
        }                                                             \
    }                                                                 \
    tmp[len] = YY_END_OF_BUFFER_CHAR;                                 \
    tmp[len + 1] = YY_END_OF_BUFFER_CHAR;                             \
                                                                      \
    struct ParseData data = { lines_index, tb, tmp, prettyprint, 0,   \
                              NULL };                                 \
    if(prettyprint) {                                                 \
        gtk_text_buffer_set_text(tb, "", 0);                          \
        data.indentstr = g_string_sized_new(16);                      \
    }                                                                 \
                                                                      \
    yyscan_t scanner;                                                 \
    prefix##lex_init_extra(&data, &scanner);                          \
    YY_BUFFER_STATE buf = prefix##_scan_buffer(tmp, len + 2, scanner);\
    prefix##set_lineno(0, scanner);                                   \
    prefix##lex(scanner);                                             \
    prefix##lex_destroy(scanner);                                     \
                                                                      \
    g_free(tmp);                                                      \
    g_array_free(lines_index, TRUE);                                  \
    if(data.indentstr) g_string_free(data.indentstr, TRUE);           \
}

struct ParseData {
    GArray* lines_index;
    GtkTextBuffer* tb;
    const gchar* text;
    gboolean prettyprint;
    int indentsize;
    GString* indentstr;
};

void mark_text(struct ParseData* pd, const gchar* text, size_t length,
               const gchar* tagname, const gchar* first_tag_prop_name, ...);
void mark_eol(struct ParseData* pd);
void reset_indent(struct ParseData* pd);
void inc_indent(struct ParseData* pd);
void dec_indent(struct ParseData* pd);
